home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / os2tools / aping / cpicerr.c < prev    next >
Encoding:
Text File  |  1992-06-15  |  55.6 KB  |  1,468 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME: CPICERR.C
  4.  *
  5.  *  COPYRIGHTS:
  6.  *             This module contains code made available by IBM
  7.  *             Corporation on an AS IS basis.  Any one receiving the
  8.  *             module is considered to be licensed under IBM copyrights
  9.  *             to use the IBM-provided source code in any way he or she
  10.  *             deems fit, including copying it, compiling it, modifying
  11.  *             it, and redistributing it, with or without
  12.  *             modifications.  No license under any IBM patents or
  13.  *             patent applications is to be implied from this copyright
  14.  *             license.
  15.  *
  16.  *             A user of the module should understand that IBM cannot
  17.  *             provide technical support for the module and will not be
  18.  *             responsible for any consequences of use of the program.
  19.  *
  20.  *             Any notices, including this one, are not to be removed
  21.  *             from the module without the prior written consent of
  22.  *             IBM.
  23.  *
  24.  *  AUTHOR:    Peter J. Schwaller
  25.  *             VNET:     PJS at RALVM6           Tie Line: 444-4376
  26.  *             Internet: pjs@ralvm6.vnet.ibm.com     (919) 254-4376
  27.  *             John Q. Walker
  28.  *             VNET:     JOHNQ at RALVM6         Tie Line: 444-4414
  29.  *             Internet: johnq@ralvm6.vnet.ibm.com   (919) 254-4414
  30.  *
  31.  *  FUNCTION:  Contains procedures to be called for handling
  32.  *             unexpected CPI-C return codes.
  33.  *             Contains procedures to be called for handling the
  34.  *             CPI-C error information cpicerr.
  35.  *
  36.  *  AVAILABILITY:
  37.  *             These sample programs and source are also available on
  38.  *             CompuServe through the APPC Information Exchange.  To get
  39.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  40.  *             prompt.  The samples are available in the Sample Programs
  41.  *             library section.  Just search on the keyword CPICPGMS to
  42.  *             find all the samples in this series.
  43.  *
  44.  *             Updates for the sample programs and support for many more
  45.  *             CPI-C platforms will also be made available on CompuServe.
  46.  *
  47.  *  RELATED FILES:
  48.  *             CPICERR.H
  49.  *
  50.  *****************************************************************************/
  51.  
  52. /*****************************************************************************
  53.  *
  54.  * OVERVIEW OF CPICERR CALLS
  55.  *
  56.  * cpicerr_new()                      Creates a CPICERR object.
  57.  *                                    This must be done before any other
  58.  *                                    cpicerr calls can be used.
  59.  *
  60.  * These calls set values in the cpicerr object structure and affect how
  61.  * cpicerr_handle_rc reacts to errors.
  62.  *
  63.  * cpicerr_set_conv_id()              Used to extract conversation state info
  64.  * cpicerr_set_exit_level()           Level of error on which to exit
  65.  * cpicerr_set_log_file_name()        What filename to use for logging
  66.  * cpicerr_set_log_file_path()        Where the filename is
  67.  * cpicerr_set_log_level()            Level of error on which to log errors
  68.  * cpicerr_set_major_version()        8 bit int - see cpicerr_exchange_version
  69.  * cpicerr_set_minor_version()        8 bit int - see cpicerr_exchange_version
  70.  * cpicerr_set_program_name()         String - Output as part of log info
  71.  * cpicerr_set_program_info()         String - Output as part of log info
  72.  * cpicerr_set_show_level()           Level of error on which to show errors
  73.  *
  74.  * cpicerr_handle_rc()                Should be called by the program for all
  75.  *                                    UNEXPECTED return codes.
  76.  *                                    Functions performed are:
  77.  *                                       Classification of the return code
  78.  *                                       Showing partial info to end user
  79.  *                                       Logging complete info to disk
  80.  *
  81.  * cpicerr_exchange_version()         Exchanges version numbers with the
  82.  *                                    partner.  Very useful when supporting
  83.  *                                    multiple versions of a program.
  84.  *
  85.  * cpicerr_destroy()                  Destroys the CPICERR  object.
  86.  *
  87.  *
  88.  * cpicerr_classify_rc()              These are internal calls used by
  89.  * cpicerr_show_rc()                  other cpicerr_handle_rc.
  90.  * cpicerr_log_cpicerr()
  91.  * cpicerr_get_message()
  92.  * cpicerr_free_cpicerr()
  93.  * cpicerr_set_rc_info()
  94.  * cpicerr_show_product_info()
  95.  *
  96.  *****************************************************************************/
  97.  
  98. /* My CPI-C include file */
  99. /* Hides CMC.H differences among platforms */
  100. #include "cpiccmc.h"
  101.  
  102. #ifdef GET_OS2_SENSE_DATA
  103. #include <appc_c.h>
  104. #endif
  105.  
  106. /* Collection of routines with special ported version for each platform */
  107. #include "cpicport.h"
  108.  
  109. #include <stdio.h>                          /* C library includes            */
  110. #include <stdlib.h>
  111. #include <string.h>
  112.  
  113. #ifndef TIME_NOT_SUPPORTED
  114. #include <time.h>
  115. #endif
  116.  
  117.  
  118. #include "cpicerr.h"                        /* CPI-C error handling vars.    */
  119.  
  120.  
  121. /*****************************************************************************
  122.  *
  123.  *  cpicerr_new()
  124.  *
  125.  *  Usage:
  126.  *  This function creates a CPICERR object which should be used on all
  127.  *  subsequent calls to cpicerr.  If an error occurs and a valid object
  128.  *  cannot be created, NULL will be returned.
  129.  *
  130.  *****************************************************************************/
  131. CPICERR *
  132. cpicerr_new(void)
  133. {
  134.     CPICERR *  cpicerr;
  135.  
  136.     cpicerr = (CPICERR *) malloc(sizeof(*cpicerr));
  137.     if (cpicerr == NULL) {
  138.         return NULL;
  139.     }
  140.  
  141.     /*-----------------------------------------------------------------------*
  142.      * Zero out the whole cpicerr.
  143.      * This is a failsafe for any fields in CPICERR which we don't explicitly
  144.      * initialize to a value.
  145.      *-----------------------------------------------------------------------*/
  146.     memset((void *)cpicerr,
  147.            (int)0,
  148.            (size_t)sizeof(CPICERR));
  149.  
  150.     /*-----------------------------------------------------------------------*
  151.      * Save the time of program initialization.
  152.      *-----------------------------------------------------------------------*/
  153. #ifndef TIME_NOT_SUPPORTED
  154.     time(&(cpicerr->program_start_time));
  155. #endif
  156.  
  157.     /*-----------------------------------------------------------------------*
  158.      * Indicate that the conversation id field has not been set.
  159.      *-----------------------------------------------------------------------*/
  160.     cpicerr->conv_id_set = FALSE;
  161.  
  162.     /*-----------------------------------------------------------------------*
  163.      * Initialize version levels.  0 indicates they have not been set.
  164.      *-----------------------------------------------------------------------*/
  165.     cpicerr->major_version = 0;
  166.     cpicerr->minor_version = 0;
  167.  
  168.     /*-----------------------------------------------------------------------*
  169.      * Initialize to always exit after an error occurs.
  170.      *-----------------------------------------------------------------------*/
  171.     cpicerr->exit_level = ALL_ERRORS;
  172.  
  173.     /*-----------------------------------------------------------------------*
  174.      * Initialize to always show errors.
  175.      *-----------------------------------------------------------------------*/
  176.     cpicerr->show_level = ALL_ERRORS;
  177.  
  178.     /*-----------------------------------------------------------------------*
  179.      * Initialize to always log errors.
  180.      *-----------------------------------------------------------------------*/
  181.     cpicerr->log_level = ALL_ERRORS;
  182.  
  183.     /*-----------------------------------------------------------------------*
  184.      * Initialize strings to NULL in case 0 != NULL
  185.      *-----------------------------------------------------------------------*/
  186.     cpicerr->program_name  = NULL;
  187.     cpicerr->program_info  = NULL;
  188.     cpicerr->log_file_name = NULL;
  189.     cpicerr->log_file_path = NULL;
  190.  
  191.     return cpicerr;
  192. }
  193.  
  194. /*****************************************************************************
  195.  *
  196.  *  cpicerr_set_conv_id
  197.  *
  198.  *  Usage:
  199.  *  This call should be used just before the cmallc call (for clients),
  200.  *  or just after the cmaccp call (for servers).
  201.  *
  202.  *  This routine will save the conversation id, as well as partner information
  203.  *  and conversation status which can be extracted from CPI-C.
  204.  *
  205.  *  This information is often helpful for debugging and in many cases cannot
  206.  *  be obtained after an error occurs, since you no longer have a valid
  207.  *  conversation id after the conversation has been deallocated.
  208.  *
  209.  *****************************************************************************/
  210. int
  211. cpicerr_set_conv_id(CPICERR * cpicerr,
  212.                     unsigned char * cm_conv_id)
  213. {
  214.     CM_RETURN_CODE        conv_rc;          /* Return code from CPI-C call   */
  215.     CM_SYNC_LEVEL         sync_level;
  216.     int   rc;                               /* return value for function     */
  217.     CM_CONVERSATION_TYPE  conversation_type;
  218.  
  219.  
  220.     if (cpicerr != (CPICERR *)NULL) {
  221.         /*-------------------------------------------------------------------*
  222.          * Save the conversation ID.
  223.          * This can often be used in conjunction with error logs or trace
  224.          * utilities.
  225.          *-------------------------------------------------------------------*/
  226.         memcpy(cpicerr->conversation_id,
  227.                cm_conv_id,
  228.                sizeof(cpicerr->conversation_id));
  229.  
  230.         /*-------------------------------------------------------------------*
  231.          * Extract the conversation type.
  232.          * Not all CPI-C implementations support Extract_Conversation_State.
  233.          * The #define statement for ECT_NOT_SUPPORTED is in CPICCMC.H.
  234.          *-------------------------------------------------------------------*/
  235. #ifndef ECT_NOT_SUPPORTED
  236.         cmect(cm_conv_id,                   /* Current conversation ID       */
  237.               &conversation_type,           /* Returned conversation type    */
  238.               &conv_rc);                    /* Put the return code here      */
  239.         if (conv_rc == CM_OK)
  240.             cpicerr->conversation_type = conversation_type;
  241. #else
  242.         cpicerr->conversation_type = CMECT_NOT_SUPPORTED;
  243. #endif
  244.  
  245.         /*-------------------------------------------------------------------*
  246.          * Extract the mode name used for this conversation.
  247.          *-------------------------------------------------------------------*/
  248.         cmemn(cm_conv_id,                   /* Current conversation ID       */
  249.               cpicerr->mode_name,           /* Returned mode name            */
  250.               &(cpicerr->mode_name_length), /* Returned mode name length     */
  251.               &conv_rc);                    /* Put the return code here      */
  252.         if (conv_rc == CM_OK) {
  253.             cpicerr->mode_name[(int)cpicerr->mode_name_length] = '\0';
  254.         }
  255.  
  256.         /*-------------------------------------------------------------------*
  257.          * Extract the partner's LU name.
  258.          *-------------------------------------------------------------------*/
  259.         cmepln(cm_conv_id,                  /* Current conversation ID       */
  260.                cpicerr->partner_LU_name,    /* Returned partner LU           */
  261.                &(cpicerr->partner_LU_name_length),/* Partner LU name length  */
  262.                &conv_rc);                   /* Put the return code here      */
  263.         if (conv_rc == CM_OK) {
  264.              cpicerr->partner_LU_name[(int)cpicerr->partner_LU_name_length]
  265.                                                                         = '\0';
  266.         }
  267.  
  268.         /*-------------------------------------------------------------------*
  269.          * Extract the conversation sync level.
  270.          *-------------------------------------------------------------------*/
  271.         cmesl(cm_conv_id,                   /* Current conversation ID       */
  272.               &sync_level,                  /* Returned sync level           */
  273.               &conv_rc);                    /* Put the return code here      */
  274.         if (conv_rc == CM_OK)
  275.             cpicerr->sync_level = sync_level;
  276.  
  277.         rc = 0;
  278.     } else {
  279.         rc = 1;
  280.     }
  281.     return rc;
  282. }
  283.  
  284. /*****************************************************************************
  285.  *
  286.  *  cpicerr_set_exit_level
  287.  *
  288.  *  Usage:
  289.  *  Specify the CPI-C error classification as the exit level.
  290.  *  When cpicerr_handle_rc() is called, the return code will be classified.
  291.  *  If the classification is above the exit level, the program will be
  292.  *  terminated (after conversation cleanup).
  293.  *
  294.  *  A value of ALL_ERRORS can be used to force an exit on any call to
  295.  *  cpicerr_handle_rc().  This is the DEFAULT value.
  296.  *
  297.  *  A value of NO_ERRORS can be used to indicate that cpicerr should never
  298.  *  cause an exit.  Your application should handle all exit termination.
  299.  *  This is especially useful when using more than one conversation.
  300.  *
  301.  *  Also see:
  302.  *      cpicerr_set_log_level
  303.  *      cpicerr_set_show_level
  304.  *****************************************************************************/
  305. int
  306. cpicerr_set_exit_level(CPICERR *        cpicerr,
  307.                        CPIC_RC_HANDLING exit_level)
  308. {
  309.     cpicerr->exit_level = exit_level;
  310.     return 0;
  311. }
  312.  
  313. /*****************************************************************************
  314.  *
  315.  *  cpicerr_set_log_file_name
  316.  *
  317.  *  Usage:
  318.  *  Sets the name of the log file to be used in cpicerr_handle_rc() to
  319.  *  log complete error information.  No attempt is made to verify that
  320.  *  the log_file_name specified is a valid filename or whether the file
  321.  *  can be opened.  If the log_file_name cannot be opened when logging
  322.  *  needs to be done, all log output will be sent to stderr instead.
  323.  *
  324.  *  For environments that support directory structures, you should specify
  325.  *  the filename on cpicerr_set_log_file_name and the directory on
  326.  *  cpicerr_set_log_file_path.  This allows your program to be isolated
  327.  *  from changes in environments that only support a single level
  328.  *  of directory (for example, VM).
  329.  *
  330.  *  Also see:
  331.  *      cpicerr_set_log_file_path
  332.  *      cpicerr_log_cpicerr (internal)
  333.  *****************************************************************************/
  334. cpicerr_set_log_file_name(CPICERR * cpicerr,
  335.                           char * log_file_name)
  336. {
  337.     /*-----------------------------------------------------------------------*
  338.      * Initialize the name of the log file.
  339.      *-----------------------------------------------------------------------*/
  340.     cpicerr->log_file_name = (char *) malloc(strlen(log_file_name)+1);
  341.     if (cpicerr->log_file_name != NULL) {
  342.         strcpy(cpicerr->log_file_name, log_file_name);
  343.         return 0;
  344.     } else {
  345.         return 1;
  346.     }
  347.  
  348. }
  349.  
  350. /*****************************************************************************
  351.  *
  352.  *  cpicerr_set_log_file_path
  353.  *
  354.  *  Usage:
  355.  *  Specifies the path qualifier for the log file name specified in the
  356.  *  cpicerr_set_log_file_name call.  If cpicerr_set_log_file_path is used
  357.  *  without setting the log file name, no error logging will occur.
  358.  *
  359.  *  If you specify a string whose first character is a $, the rest of the
  360.  *  string will be looked for as an environment variable.  For example,
  361.  *  in OS/2, you put the following in your CONFIG.SYS:
  362.  *  SET LOGPATH=d:\logfiles
  363.  *
  364.  *  then specify $LOGPATH as a parameter on cpicerr_set_log_file_path.
  365.  *
  366.  *****************************************************************************/
  367. cpicerr_set_log_file_path(CPICERR * cpicerr,
  368.                           char * log_file_path)
  369. {
  370.     char * path;
  371.  
  372.     /*-----------------------------------------------------------------------*
  373.      * Initialize the name of the log file.
  374.      *-----------------------------------------------------------------------*/
  375.     if (log_file_path[0] == '$') {
  376.         path = getenv(&log_file_path[1]);
  377.         if (path == NULL) {
  378.             return 1;
  379.         }
  380.     } else {
  381.         path = log_file_path;
  382.     }
  383.  
  384.     cpicerr->log_file_path = (char *) malloc(strlen(path)+1);
  385.     if (cpicerr->log_file_path != NULL) {
  386.         strcpy(cpicerr->log_file_path, path);
  387.         return 0;
  388.     } else {
  389.         return 1;
  390.     }
  391.  
  392. }
  393.  
  394. /*****************************************************************************
  395.  *
  396.  *  cpicerr_set_log_level
  397.  *
  398.  *  Usage:
  399.  *  Specify the CPI-C error classification as the log level.
  400.  *  When cpicerr_handle_rc() is called, the return code will be classified.
  401.  *  If the classification is above the log level, the return code and
  402.  *  conversation information will be logged to the log file specified
  403.  *  with the cpicerr_set_log_file_name and cpicerr_set_log_file_path.
  404.  *
  405.  *  A value of ALL_ERRORS can be used to force logging on any call to
  406.  *  cpicerr_handle_rc().  This is the DEFAULT value.  This is especially
  407.  *  useful when used on servers.
  408.  *
  409.  *  A value of NO_ERRORS can be used to indicate that cpicerr should never
  410.  *  cause an error log.  Your application should handle all error logging.
  411.  *
  412.  *  Also see:
  413.  *      cpicerr_set_log_file_name
  414.  *      cpicerr_set_log_file_path
  415.  *      cpicerr_log_cpicerr (internal)
  416.  *      cpicerr_set_exit_level
  417.  *      cpicerr_set_show_level
  418.  *****************************************************************************/
  419. int
  420. cpicerr_set_log_level(CPICERR *        cpicerr,
  421.                       CPIC_RC_HANDLING log_level)
  422. {
  423.     cpicerr->log_level = log_level;
  424.     return 0;
  425. }
  426.  
  427. /*****************************************************************************
  428.  *
  429.  *  cpicerr_set_major_version
  430.  *
  431.  *  Usage:
  432.  *  Sets the major version number for the application.
  433.  *  The version number can be 0-255.
  434.  *
  435.  *  The version number is used on error logging and by the
  436.  *  cpicerr_exchange_version() call.
  437.  *
  438.  *  Also see:
  439.  *      cpicerr_set_minor_version
  440.  *****************************************************************************/
  441. int cpicerr_set_major_version(  CPICERR * cpicerr,
  442.                                 char major_version)
  443. {
  444.     cpicerr->major_version = major_version;
  445.     return 0;
  446. }
  447.  
  448. /*****************************************************************************
  449.  *
  450.  *  cpicerr_set_minor_version
  451.  *
  452.  *  Usage:
  453.  *  Sets the minor version number for the application.
  454.  *  The version number can be 0-255.
  455.  *
  456.  *  The version number is used on error logging and by the
  457.  *  cpicerr_exchange_version() call.
  458.  *
  459.  *  Also see:
  460.  *      cpicerr_set_major_version
  461.  *****************************************************************************/
  462. int cpicerr_set_minor_version(  CPICERR * cpicerr,
  463.                                 char minor_version)
  464. {
  465.     cpicerr->minor_version = minor_version;
  466.     return 0;
  467. }
  468.  
  469.  
  470. /*****************************************************************************
  471.  *
  472.  *  cpicerr_set_program_info
  473.  *
  474.  *  Usage:
  475.  *  Sets a program information string that is included in the log information.
  476.  *****************************************************************************/
  477. cpicerr_set_program_info( CPICERR * cpicerr,
  478.                           char * program_info)
  479. {
  480.     /*-----------------------------------------------------------------------*
  481.      * Save the application's program information string
  482.      *-----------------------------------------------------------------------*/
  483.     cpicerr->program_info = (char *) malloc(strlen(program_info)+1);
  484.     if (cpicerr->program_info != NULL) {
  485.         strcpy(cpicerr->program_info, program_info);
  486.         return 0;
  487.     } else {
  488.         return 1;
  489.     }
  490. }
  491.  
  492.  
  493. /*****************************************************************************
  494.  *
  495.  *  cpicerr_set_program_name
  496.  *
  497.  *  Usage:
  498.  *  Sets a program name string that is included in the log information.
  499.  *****************************************************************************/
  500. cpicerr_set_program_name(CPICERR * cpicerr,
  501.                          char * program_name)
  502. {
  503.     /*-----------------------------------------------------------------------*
  504.      * Save the local program name.
  505.      *-----------------------------------------------------------------------*/
  506.     cpicerr->program_name = (char *) malloc(strlen(program_name)+1);
  507.     if (cpicerr->program_name != NULL) {
  508.         strcpy(cpicerr->program_name, program_name);
  509.         return 0;
  510.     } else {
  511.         return 1;
  512.     }
  513. }
  514.  
  515.  
  516. /*****************************************************************************
  517.  *
  518.  *  cpicerr_set_show_level
  519.  *
  520.  *  Usage:
  521.  *  Specify the CPI-C error classification as the show level.
  522.  *  When cpicerr_handle_rc() is called, the return code will be classified.
  523.  *  If the classification is above the show level, the return code and
  524.  *  some conversation information will be shown to the user.
  525.  *
  526.  *  A value of ALL_ERRORS can be used to force showing of all calls to
  527.  *  cpicerr_handle_rc().  This is the DEFAULT value.
  528.  *
  529.  *  A value of NO_ERRORS can be used to indicate that cpicerr should never
  530.  *  cause an error to be shown to the user.
  531.  *
  532.  *  Also see:
  533.  *      cpicerr_set_exit_level
  534.  *      cpicerr_set_log_level
  535.  *****************************************************************************/
  536. int
  537. cpicerr_set_show_level(CPICERR *        cpicerr,
  538.                        CPIC_RC_HANDLING show_level)
  539. {
  540.     cpicerr->show_level = show_level;
  541.     return 0;
  542. }
  543.  
  544.  
  545. /******************************************************************************
  546.  *
  547.  *  cpicerr_handle_rc
  548.  *
  549.  *  Usage:
  550.  *  This function should be called to handle any unexpected CPI-C return
  551.  *  codes.  The exact function of this routine depends upon the settings
  552.  *  that have been made to the CPICERR object.
  553.  *
  554.  *  Functions include:
  555.  *      Determining the current conversation state
  556.  *      Classifying the return code (CPIC_RC_HANDLING enum)
  557.  *      Showing return code info to the user
  558.  *      Logging the return code and conversation info to disk
  559.  *      Deallocate the conversation and exit
  560.  *
  561.  *  Also see:
  562.  *      cpicerr_set_exit_level
  563.  *      cpicerr_set_log_level
  564.  *      cpicerr_set_show_level
  565.  *
  566.  *****************************************************************************/
  567. CPIC_RC_HANDLING
  568. cpicerr_handle_rc(CPICERR * cpicerr,
  569.                   CPIC_VERB_INDEX verb_index,
  570.                   CM_RETURN_CODE conv_rc)
  571.  
  572. {
  573.    /* Displays the CPI-C return code and the verb name. */
  574.  
  575.     CM_RETURN_CODE cm_rc;                   /* Return code from CPI-C call   */
  576.     CPIC_RC_HANDLING classification;        /* Returned RC classification    */
  577.     char * string;                          /* temp var for output strings   */
  578.     FILE *target_file;                      /* where to send messages        */
  579.     CM_CONVERSATION_STATE conversation_state; /* Current conv. state         */
  580.  
  581.     /*-----------------------------------------------------------------------*
  582.      * Extract the current conversation state.
  583.      * This will not be useful if the conversation has failed or a deallocate
  584.      * return code has been received.  The conversation state is most useful
  585.      * when a state check has occurred.
  586.      *-----------------------------------------------------------------------*/
  587. #ifndef ECS_NOT_SUPPORTED
  588.      cmecs(cpicerr->conversation_id,
  589.            &conversation_state,
  590.            &cm_rc);
  591.      if (cm_rc == CM_OK) {
  592.          cpicerr->conversation_state = conversation_state;
  593.      }
  594. #else
  595.      cpicerr->conversation_state = CMECS_NOT_SUPPORTED;
  596. #endif
  597.  
  598.     /*-----------------------------------------------------------------------*
  599.      * Store the error information in the cpicerr
  600.      *-----------------------------------------------------------------------*/
  601.      cpicerr_set_rc_info(cpicerr, verb_index, conv_rc);
  602.  
  603.     /*-----------------------------------------------------------------------*
  604.      * Set the target for the printed information about the error.
  605.      *-----------------------------------------------------------------------*/
  606.     target_file = stderr;
  607.  
  608.     /*-----------------------------------------------------------------------*
  609.      * Get the classification for this return code.
  610.      *-----------------------------------------------------------------------*/
  611.     cpicerr_classify_rc(conv_rc, &classification);
  612.  
  613.     /*-----------------------------------------------------------------------*
  614.      * Show the CPI-C verb and return code.
  615.      *-----------------------------------------------------------------------*/
  616.     if (classification >= cpicerr->show_level) {
  617.         cpicerr_show_rc(cpicerr, target_file);
  618.     }
  619.  
  620.  
  621.     /*-----------------------------------------------------------------------*
  622.      * Show the classification for this return code.
  623.      *-----------------------------------------------------------------------*/
  624.     if (classification >= cpicerr->show_level) {
  625.         string = cpicerr_get_message(CPIC_RC_CLASSES, classification);
  626.         fprintf(target_file, "       return code class: %s\n",
  627.                 string);
  628.         /*-----------------------------------------------------------------------*
  629.          * Show product specific information associated with this error.
  630.          *-----------------------------------------------------------------------*/
  631.         cpicerr_show_product_info(cpicerr, target_file);
  632.     }
  633.  
  634.  
  635.     /*-----------------------------------------------------------------------*
  636.      * Log this error, along with the infomation in its cpicerr.
  637.      *-----------------------------------------------------------------------*/
  638.     if (classification >= cpicerr->log_level) {
  639.         cpicerr_log_cpicerr(cpicerr);
  640.     }
  641.  
  642.  
  643.     if (classification >= cpicerr->exit_level) {
  644.         CM_INT32 deallocate_type;
  645.         /*-------------------------------------------------------------------*
  646.          * Exit the application, rather than returning to the caller.
  647.          *-------------------------------------------------------------------*/
  648.         deallocate_type = CM_DEALLOCATE_ABEND;
  649.  
  650.         cmsdt(cpicerr -> conversation_id,
  651.               &deallocate_type,
  652.               &cm_rc);
  653.  
  654.         cmdeal(cpicerr -> conversation_id,
  655.                &cm_rc);
  656.  
  657.         exit(EXIT_FAILURE);                 /* Set a failure return code     */
  658.     }
  659.     return classification;
  660. }
  661.  
  662.  
  663. /******************************************************************************
  664.  *
  665.  *  cpicerr_exchange_version
  666.  *
  667.  *****************************************************************************/
  668.  
  669. int
  670. cpicerr_exchange_version(CPICERR * cpicerr,
  671.                          unsigned char *    cm_conv_id,
  672.                          CM_INT32  conv_state,
  673.                          char *    partner_major_version,
  674.                          char *    partner_minor_version)
  675. {
  676.     CM_SEND_TYPE send_type;                 /* CPI-C send type               */
  677.     CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive; /* CPI-C prepare to receive  */
  678.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  679.     CM_INT32    length;                     /* generic length variable       */
  680.     CM_INT32    rts_received;               /* request to send received      */
  681.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  682.     CM_INT32    what_received;              /* What received parm from CMRCV */
  683.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  684.     CM_INT32    status_received;            /* Status from CMRCV             */
  685.     unsigned char buffer[128];              /* data buffer                   */
  686.  
  687.     *partner_major_version = 0;
  688.     *partner_minor_version = 0;
  689.  
  690.     prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
  691.     cmsptr(cm_conv_id,                      /* Set prepare to receive type   */
  692.            &prep_to_receive,
  693.            &cm_rc);
  694.     /* The only expected return code is CM_OK */
  695.     if (cm_rc != CM_OK) return cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
  696.  
  697.     send_type = CM_BUFFER_DATA;
  698.     cmsst(cm_conv_id,                       /* Set send type                 */
  699.           &send_type,
  700.           &cm_rc);
  701.     if (cm_rc != CM_OK) return cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  702.  
  703.  
  704.     switch (conv_state) {
  705.     case CM_SEND_STATE:
  706.         buffer[0] = CPICERR_EXCHANGE_VERSION;
  707.         buffer[1] = cpicerr->major_version;
  708.         buffer[2] = cpicerr->minor_version;
  709.         length = 3;
  710.         cmsend(cm_conv_id,
  711.                buffer,
  712.                &length,
  713.                &rts_received,
  714.                &cm_rc);
  715.         /* The only expected return code is CM_OK */
  716.         if (cm_rc != CM_OK)
  717.             return cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  718.         /* this falls through to the receive code!!! */
  719.     case CM_RECEIVE_STATE:
  720.         max_receive_len = 3;
  721.         cmrcv (cm_conv_id,
  722.                buffer,
  723.                &max_receive_len,
  724.                &what_received,
  725.                &received_len,
  726.                &status_received,
  727.                &rts_received,
  728.                &cm_rc);
  729.         if (cm_rc == CM_OK) {
  730.             if (what_received != CM_NO_DATA_RECEIVED) {
  731.                 if (received_len > 2 && buffer[0]==CPICERR_EXCHANGE_VERSION) {
  732.                     *partner_major_version = buffer[1];
  733.                     *partner_minor_version = buffer[2];
  734.                 }
  735.             }
  736.             switch (status_received) {
  737.             case CM_CONFIRM_RECEIVED:
  738.                 cmcfmd(cm_conv_id,
  739.                        &cm_rc);
  740.                 if (cm_rc != CM_OK)
  741.                     return cpicerr_handle_rc(cpicerr, MSG_CMCFMD, cm_rc);
  742.                 break;
  743.             case CM_SEND_RECEIVED:
  744.                 /* This is good, we don't have to do anything. */
  745.                 break;
  746.             default:
  747.                 ;
  748.                 /* should do a reply_error here */
  749.  
  750.             }
  751.         } else {
  752.             return cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  753.         }
  754.         break;
  755.     default:
  756.         /* do a reply error here */
  757.         return UNRECOVERABLE;
  758.     }
  759.  
  760.     if ((conv_state == CM_RECEIVE_STATE) &&
  761.          (status_received == CM_SEND_RECEIVED)) {
  762.         buffer[0] = CPICERR_EXCHANGE_VERSION;
  763.         buffer[1] = cpicerr->major_version;
  764.         buffer[2] = cpicerr->minor_version;
  765.         length = 3;
  766.         cmsend(cm_conv_id,
  767.                buffer,
  768.                &length,
  769.                &rts_received,
  770.                &cm_rc);
  771.         /* The only expected return code is CM_OK */
  772.  
  773.         if (cm_rc != CM_OK)
  774.             return cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  775.  
  776.         cmptr(cm_conv_id,
  777.               &cm_rc);
  778.         if (cm_rc != CM_OK)
  779.             return cpicerr_handle_rc(cpicerr, MSG_CMPTR, cm_rc);
  780.     }
  781.     return RC_OK;
  782. }
  783.  
  784. /*****************************************************************************
  785.  *
  786.  *  cpicerr_destroy()
  787.  *
  788.  *****************************************************************************/
  789. void
  790. cpicerr_destroy(CPICERR * cpicerr)
  791. {
  792.     cpicerr_free_cpicerr(cpicerr);
  793.     return;
  794. }
  795.  
  796.  
  797.  
  798. /*****************************************************************************
  799.  *
  800.  *  cpicerr_set_rc_info
  801.  *
  802.  *****************************************************************************/
  803. void
  804. cpicerr_set_rc_info(CPICERR *       cpicerr,
  805.                     CPIC_VERB_INDEX verb_index,
  806.                     CM_RETURN_CODE  conv_rc)
  807. /* Store the verb return code information into the cpicerr structure */
  808. {
  809.     cpicerr->verb_index = verb_index;
  810.     cpicerr->conv_rc = conv_rc;
  811. }
  812.  
  813. /*****************************************************************************
  814.  *
  815.  *  cpicerr_show_rc
  816.  *
  817.  *****************************************************************************/
  818. void
  819. cpicerr_show_rc(CPICERR * cpicerr,
  820.                 FILE * target_file)
  821. {
  822.     fprintf(target_file, "\n  Unexpected CPI-C return code encountered...\n");
  823.  
  824.     /*-----------------------------------------------------------------------*
  825.      * Find the CPI-C verb's name, and show it.
  826.      *-----------------------------------------------------------------------*/
  827.     fprintf(target_file, "         CPI-C verb name: %s, %s\n",
  828.             cpicerr_get_message(CPIC_VERBS_SHORT,
  829.                                 (CM_INT32)cpicerr->verb_index),
  830.             cpicerr_get_message(CPIC_VERBS_LONG,
  831.                                 (CM_INT32)cpicerr->verb_index));
  832.  
  833.     /*-----------------------------------------------------------------------*
  834.      * Find the CPI-C return code's name, and show it.
  835.      *-----------------------------------------------------------------------*/
  836.     fprintf(target_file, "       CPI-C return code: %lu, %s\n",
  837.             cpicerr->conv_rc,
  838.             cpicerr_get_message(CPIC_RETURN_CODES, cpicerr->conv_rc));
  839.  
  840.     return;
  841. }
  842.  
  843.  
  844. /*****************************************************************************
  845.  *
  846.  *  cpicerr_classify_rc
  847.  *
  848.  *****************************************************************************/
  849. void
  850. cpicerr_classify_rc (CM_RETURN_CODE conv_rc,
  851.                      CPIC_RC_HANDLING * classification)
  852. {
  853.     switch (conv_rc) {
  854.  
  855.         case CM_ALLOCATE_FAILURE_NO_RETRY:
  856.             /* configuration defect or protocol defect, local or partner */
  857.         case CM_TP_NOT_AVAILABLE_NO_RETRY:
  858.             /* partner program could not be sucessfully started */
  859.         case CM_RESOURCE_FAILURE_NO_RETRY:
  860.             /* communication failure or protocol defect, local or partner */
  861.  
  862.         case CM_DEALLOCATED_ABEND:
  863.             /* unrecoverable error in the partner TP */
  864.         case CM_DEALLOCATED_ABEND_SVC:
  865.             /* unrecoverable error in the partner TP */
  866.         case CM_DEALLOCATED_ABEND_TIMER:
  867.             /* unrecoverable error in the partner TP */
  868.  
  869.         case CM_CONVERSATION_TYPE_MISMATCH:
  870.         case CM_PIP_NOT_SPECIFIED_CORRECTLY:
  871.         case CM_SYNC_LVL_NOT_SUPPORTED_LU:
  872.         case CM_SYNC_LVL_NOT_SUPPORTED_PGM:
  873.         case CM_TPN_NOT_RECOGNIZED:
  874.             /* configuration defect or mismatch with the partner */
  875.  
  876.         case CM_OK:
  877.             /* application design defect, local or partner program */
  878.         case CM_DEALLOCATED_NORMAL:
  879.             /* TP design defect, local or partner program */
  880.         case CM_PARAMETER_ERROR:
  881.             /* local program design or coding defect */
  882.         case CM_PROGRAM_PARAMETER_CHECK:
  883.             /* local program design or coding defect */
  884.         case CM_PROGRAM_STATE_CHECK:
  885.             /* local program design or coding defect */
  886.             *classification = UNRECOVERABLE;
  887.             break;
  888.  
  889.         case CM_ALLOCATE_FAILURE_RETRY:
  890.             /* configuration defect or route temporarily down */
  891.         case CM_TP_NOT_AVAILABLE_RETRY:
  892.             /* congestion at the partner operating system */
  893.         case CM_RESOURCE_FAILURE_RETRY:
  894.             /* route temporarily down */
  895.             *classification = RETRY_CONV;
  896.             break;
  897.  
  898.         case CM_UNSUCCESSFUL:
  899.             /* verb could not be completed now */
  900.             *classification = RETRY_VERB;
  901.             break;
  902.  
  903.         case CM_PROGRAM_ERROR_NO_TRUNC:
  904.         case CM_SVC_ERROR_NO_TRUNC:
  905.             /* partner failed while building a record to send */
  906.         case CM_PROGRAM_ERROR_PURGING:
  907.         case CM_SVC_ERROR_PURGING:
  908.             /* partner failed while processing a received record */
  909.         case CM_PROGRAM_ERROR_TRUNC:
  910.         case CM_SVC_ERROR_TRUNC:
  911.             /* partner failed after partially sending a record */
  912.             *classification = ERROR_RECEIVED;
  913.             break;
  914.  
  915.         case CM_PRODUCT_SPECIFIC_ERROR:
  916.             /********************************/
  917.             /* Examine each of these.       */
  918.             /* In some cases, you may want  */
  919.             /* to return CONTINUE.          */
  920.             /********************************/
  921.             *classification = UNRECOVERABLE;
  922.             break;
  923.  
  924.         case CM_SECURITY_NOT_VALID:
  925.             *classification = SECURITY_NOT_VALID;
  926.             break;
  927.  
  928.         case CM_RESOURCE_FAILURE_RETRY_BO:
  929.             /********************************/
  930.             /* Syncpoint values             */
  931.             /********************************/
  932.             *classification = RETRY_CONV_BO;
  933.             break;
  934.  
  935.         case CM_TAKE_BACKOUT:
  936.             /********************************/
  937.             /* Syncpoint values             */
  938.             /********************************/
  939.             *classification = BACKOUT_RECEIVED;
  940.             break;
  941.  
  942.         case CM_DEALLOCATED_ABEND_BO:
  943.         case CM_DEALLOCATED_ABEND_SVC_BO:
  944.         case CM_DEALLOCATED_ABEND_TIMER_BO:
  945.         case CM_RESOURCE_FAIL_NO_RETRY_BO:
  946.         case CM_DEALLOCATED_NORMAL_BO:
  947.             /********************************/
  948.             /* Syncpoint values             */
  949.             /********************************/
  950.             *classification = UNRECOVERABLE_BO;
  951.             break;
  952.  
  953.         default:
  954.             *classification = UNRECOVERABLE;
  955.             break;
  956.     }
  957.     return;
  958. }
  959.  
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966. /*****************************************************************************
  967.  *
  968.  *  cpicerr_log_cpicerr()
  969.  *
  970.  *****************************************************************************/
  971. int
  972. cpicerr_log_cpicerr(CPICERR * cpicerr)
  973. {
  974.     int rc;                                 /* return value                  */
  975.     FILE *log_file;                         /* log file handle               */
  976.     unsigned count;                         /* used to extract text strings  */
  977.     char filepath[256];                     /* actual file path for logging  */
  978.     char last_char;
  979.  
  980.     if (cpicerr != (CPICERR *)NULL) {
  981.  
  982.         /*-------------------------------------------------------------------*
  983.          * Save the time of the call to this procedure.
  984.          *-------------------------------------------------------------------*/
  985. #ifndef TIME_NOT_SUPPORTED
  986.         time(&(cpicerr->program_error_time));
  987. #endif
  988.  
  989.         filepath[0] = '\0';
  990.         if (cpicerr->log_file_path != NULL) {
  991.             strcpy(filepath, cpicerr->log_file_path);
  992.             last_char =
  993.                     cpicerr->log_file_path[strlen(cpicerr->log_file_path)-1];
  994.             if (!(last_char == '\\' || last_char == '/')) {
  995.                 strcat(filepath, "/");
  996.             }
  997.         }
  998.         if (cpicerr->log_file_name != NULL) {
  999.             strcat(filepath, cpicerr->log_file_name);
  1000.         }
  1001.  
  1002.         if ((strlen(filepath) == 0) ||
  1003.                                ((log_file = fopen(filepath, "a")) == NULL  )) {
  1004.             log_file = stderr;
  1005.         }
  1006.  
  1007.         if (cpicerr->program_name != NULL) {
  1008.             fprintf(log_file, "  CPI-C error in program: \"%s\"",
  1009.                                                      cpicerr->program_name);
  1010.         }
  1011.  
  1012.  
  1013.         if (cpicerr->program_info != NULL) {
  1014.             fprintf(log_file, ", %s", cpicerr->program_info);
  1015.         }
  1016.         fprintf(log_file, "\n");
  1017.  
  1018.         if (cpicerr->major_version != 0 || cpicerr->minor_version != 0) {
  1019.             fprintf(log_file, "         Program version: %u.%u\n",
  1020.                                        (unsigned int)cpicerr->major_version,
  1021.                                        (unsigned int)cpicerr->minor_version);
  1022.         }
  1023.  
  1024.  
  1025.         cpicerr_show_rc(cpicerr, log_file);
  1026.  
  1027.         fprintf(log_file, "   CPI-C conversation ID: ");
  1028.  
  1029.         for (count = 0; count<sizeof(cpicerr->conversation_id); count++ ) {
  1030.             fprintf(log_file, "%02X",
  1031.                                (unsigned int)cpicerr->conversation_id[count]);
  1032.         }
  1033.         fprintf(log_file, "\n");
  1034.  
  1035.         fprintf(log_file, "CPI-C conversation state: %lu, %s\n",
  1036.            cpicerr->conversation_state,
  1037.            cpicerr_get_message(CPIC_STATES_CONV, cpicerr->conversation_state));
  1038.  
  1039.         fprintf(log_file, " CPI-C conversation type: %lu, %s\n",
  1040.            cpicerr->conversation_type,
  1041.            cpicerr_get_message( CPIC_CONV_TYPES, cpicerr->conversation_type));
  1042.  
  1043.         fprintf(log_file, " Conversation sync level: %lu, %s\n",
  1044.                 cpicerr->sync_level,
  1045.                 cpicerr_get_message( CPIC_SYNC_LEVELS, cpicerr->sync_level));
  1046.  
  1047.         if (cpicerr->mode_name[0] != '\0') {
  1048.             cpicerr->mode_name[(int)cpicerr->mode_name_length] = '\0';
  1049.         }
  1050.  
  1051.         if (cpicerr->partner_LU_name[0] != '\0') {
  1052.             cpicerr->partner_LU_name[(int)cpicerr->partner_LU_name_length]
  1053.                                                                        = '\0';
  1054.         }
  1055.  
  1056.         fprintf(log_file, "         Partner LU name: %s\n",
  1057.                                                      cpicerr->partner_LU_name);
  1058.         fprintf(log_file, "               Mode name: %s\n",
  1059.                                                      cpicerr->mode_name);
  1060.  
  1061. #ifndef TIME_NOT_SUPPORTED
  1062.         fprintf(log_file, "      Program start time: %s",
  1063.                                         ctime(&(cpicerr->program_start_time)));
  1064.         fprintf(log_file, "      Program error time: %s\n",
  1065.                                         ctime(&(cpicerr->program_error_time)));
  1066. #endif
  1067.  
  1068.         fclose(log_file);
  1069.  
  1070.         rc = 0;
  1071.     } else {
  1072.         rc = 1;
  1073.     }
  1074.  
  1075.     return rc;
  1076. }
  1077.  
  1078. /*****************************************************************************
  1079.  *
  1080.  *  cpicerr_free_cpicerr()
  1081.  *
  1082.  *****************************************************************************/
  1083. void
  1084. cpicerr_free_cpicerr(CPICERR * cpicerr)
  1085. {
  1086.     if (cpicerr != NULL) {
  1087.         if (cpicerr->program_name != NULL) {
  1088.             free(cpicerr->program_name);
  1089.         }
  1090.  
  1091.         if (cpicerr->program_info != NULL) {
  1092.             free(cpicerr->program_info);
  1093.         }
  1094.  
  1095.         if (cpicerr->log_file_name != NULL) {
  1096.             free(cpicerr->log_file_name);
  1097.         }
  1098.  
  1099.         if (cpicerr->log_file_path != NULL) {
  1100.             free(cpicerr->log_file_path);
  1101.         }
  1102.  
  1103.         free(cpicerr);
  1104.     }
  1105.  
  1106.     return;
  1107. }
  1108.  
  1109.  
  1110.  
  1111. CPICERR_MESSAGE cpicerr_verbs_short[] = {
  1112.     MSG_CMACCP,         "CMACCP",
  1113.     MSG_CMALLC,         "CMALLC",
  1114.     MSG_CMCFM,          "CMCFM",
  1115.     MSG_CMCFMD,         "CMCFMD",
  1116.     MSG_CMDEAL,         "CMDEAL",
  1117.     MSG_CMECS,          "CMECS",
  1118.     MSG_CMECT,          "CMECT",
  1119.     MSG_CMEMN,          "CMEMN",
  1120.     MSG_CMEPLN,         "CMEPLN",
  1121.     MSG_CMESL,          "CMESL",
  1122.     MSG_CMFLUS,         "CMFLUS",
  1123.     MSG_CMINIT,         "CMINIT",
  1124.     MSG_CMPTR,          "CMPTR",
  1125.     MSG_CMRCV,          "CMRCV",
  1126.     MSG_CMRTS,          "CMRTS",
  1127.     MSG_CMSCT,          "CMSCT",
  1128.     MSG_CMSDT,          "CMSDT",
  1129.     MSG_CMSED,          "CMSED",
  1130.     MSG_CMSEND,         "CMSEND",
  1131.     MSG_CMSERR,         "CMSERR",
  1132.     MSG_CMSF,           "CMSF",
  1133.     MSG_CMSLD,          "CMSLD",
  1134.     MSG_CMSMN,          "CMSMN",
  1135.     MSG_CMSPLN,         "CMSPLN",
  1136.     MSG_CMSPTR,         "CMSPTR",
  1137.     MSG_CMSRC,          "CMSRC",
  1138.     MSG_CMSRT,          "CMSRT",
  1139.     MSG_CMSSL,          "CMSSL",
  1140.     MSG_CMSST,          "CMSST",
  1141.     MSG_CMSTPN,         "CMSTPN",
  1142.     MSG_CMTRTS,         "CMTRTS",
  1143.     MSG_XCSCSU,         "XCSCSU",
  1144.     MSG_XCSCSP,         "XCSCSP",
  1145.     MSG_XCSCST,         "XCSCST",
  1146.     MAX_MESSAGE,        "ERROR "
  1147. };
  1148.  
  1149. CPICERR_MESSAGE cpicerr_verbs_long[] = {
  1150.     MSG_CMACCP,         "Accept_Conversation",
  1151.     MSG_CMALLC,         "Allocate",
  1152.     MSG_CMCFM,          "Confirm",
  1153.     MSG_CMCFMD,         "Confirmed",
  1154.     MSG_CMDEAL,         "Deallocate",
  1155.     MSG_CMECS,          "Extract_Conversation_State",
  1156.     MSG_CMECT,          "Extract_Conversation_Type",
  1157.     MSG_CMEMN,          "Extract_Mode_Name",
  1158.     MSG_CMEPLN,         "Extract_Partner_LU_Name",
  1159.     MSG_CMESL,          "Extract_Sync_Level",
  1160.     MSG_CMFLUS,         "Flush",
  1161.     MSG_CMINIT,         "Initialize_Conversation",
  1162.     MSG_CMPTR,          "Prepare_To_Receive",
  1163.     MSG_CMRCV,          "Receive",
  1164.     MSG_CMRTS,          "Request_To_Send",
  1165.     MSG_CMSCT,          "Set_Conversation_Type",
  1166.     MSG_CMSDT,          "Set_Deallocate_Type",
  1167.     MSG_CMSED,          "Set_Error_Direction",
  1168.     MSG_CMSEND,         "Send_Data",
  1169.     MSG_CMSERR,         "Send_Error",
  1170.     MSG_CMSF,           "Set_Fill",
  1171.     MSG_CMSLD,          "Set_Log_Data",
  1172.     MSG_CMSMN,          "Set_Mode_Name",
  1173.     MSG_CMSPLN,         "Set_Partner_LU_Name",
  1174.     MSG_CMSPTR,         "Set_Prepare_To_Receive_Type",
  1175.     MSG_CMSRC,          "Set_Return_Control",
  1176.     MSG_CMSRT,          "Set_Receive_Type",
  1177.     MSG_CMSSL,          "Set_Sync_Level",
  1178.     MSG_CMSST,          "Set_Send_Type",
  1179.     MSG_CMSTPN,         "Set_TP_Name",
  1180.     MSG_CMTRTS,         "Test_Request_To_Send_Received",
  1181.     MSG_XCSCSU,         "Set Conversation Security Userid",
  1182.     MSG_XCSCSP,         "Set Conversation Security Password",
  1183.     MSG_XCSCST,         "Set Conversation Security Type",
  1184.     MAX_MESSAGE,        "Invalid verb name"
  1185. };
  1186.  
  1187. CPICERR_MESSAGE cpicerr_return_codes[] = {
  1188.     CM_OK,                          "CM_OK",
  1189.     CM_ALLOCATE_FAILURE_NO_RETRY,   "CM_ALLOCATE_FAILURE_NO_RETRY",
  1190.     CM_ALLOCATE_FAILURE_RETRY,      "CM_ALLOCATE_FAILURE_RETRY",
  1191.     CM_CONVERSATION_TYPE_MISMATCH,  "CM_CONVERSATION_TYPE_MISMATCH",
  1192.     CM_PIP_NOT_SPECIFIED_CORRECTLY, "CM_PIP_NOT_SPECIFIED_CORRECTLY",
  1193.     CM_SECURITY_NOT_VALID,          "CM_SECURITY_NOT_VALID",
  1194.     CM_SYNC_LVL_NOT_SUPPORTED_LU,   "CM_SYNC_LVL_NOT_SUPPORTED_LU",
  1195.     CM_SYNC_LVL_NOT_SUPPORTED_PGM,  "CM_SYNC_LVL_NOT_SUPPORTED_PGM",
  1196.     CM_TPN_NOT_RECOGNIZED,          "CM_TPN_NOT_RECOGNIZED",
  1197.     CM_TP_NOT_AVAILABLE_NO_RETRY,   "CM_TP_NOT_AVAILABLE_NO_RETRY",
  1198.     CM_TP_NOT_AVAILABLE_RETRY,      "CM_TP_NOT_AVAILABLE_RETRY",
  1199.     CM_DEALLOCATED_ABEND,           "CM_DEALLOCATED_ABEND",
  1200.     CM_DEALLOCATED_NORMAL,          "CM_DEALLOCATED_NORMAL",
  1201.     CM_PARAMETER_ERROR,             "CM_PARAMETER_ERROR",
  1202.     CM_PRODUCT_SPECIFIC_ERROR,      "CM_PRODUCT_SPECIFIC_ERROR",
  1203.     CM_PROGRAM_ERROR_NO_TRUNC,      "CM_PROGRAM_ERROR_NO_TRUNC",
  1204.     CM_PROGRAM_ERROR_PURGING,       "CM_PROGRAM_ERROR_PURGING",
  1205.     CM_PROGRAM_ERROR_TRUNC,         "CM_PROGRAM_ERROR_TRUNC",
  1206.     CM_PROGRAM_PARAMETER_CHECK,     "CM_PROGRAM_PARAMETER_CHECK",
  1207.     CM_PROGRAM_STATE_CHECK,         "CM_PROGRAM_STATE_CHECK",
  1208.     CM_RESOURCE_FAILURE_NO_RETRY,   "CM_RESOURCE_FAILURE_NO_RETRY",
  1209.     CM_RESOURCE_FAILURE_RETRY,      "CM_RESOURCE_FAILURE_RETRY",
  1210.     CM_UNSUCCESSFUL,                "CM_UNSUCCESSFUL",
  1211.     CM_DEALLOCATED_ABEND_SVC,       "CM_DEALLOCATED_ABEND_SVC",
  1212.     CM_DEALLOCATED_ABEND_TIMER,     "CM_DEALLOCATED_ABEND_TIMER",
  1213.     CM_SVC_ERROR_NO_TRUNC,          "CM_SVC_ERROR_NO_TRUNC",
  1214.     CM_SVC_ERROR_PURGING,           "CM_SVC_ERROR_PURGING",
  1215.     CM_SVC_ERROR_TRUNC,             "CM_SVC_ERROR_TRUNC",
  1216.     CM_TAKE_BACKOUT,                "CM_TAKE_BACKOUT",
  1217.     CM_DEALLOCATED_ABEND_BO,        "CM_DEALLOCATED_ABEND_BO",
  1218.     CM_DEALLOCATED_ABEND_SVC_BO,    "CM_DEALLOCATED_ABEND_SVC_BO",
  1219.     CM_DEALLOCATED_ABEND_TIMER_BO,  "CM_DEALLOCATED_ABEND_TIMER_BO",
  1220.     CM_RESOURCE_FAIL_NO_RETRY_BO,   "CM_RESOURCE_FAIL_NO_RETRY_BO",
  1221.     CM_RESOURCE_FAILURE_RETRY_BO,   "CM_RESOURCE_FAILURE_RETRY_BO",
  1222.     CM_DEALLOCATED_NORMAL_BO,       "CM_DEALLOCATED_NORMAL_BO",
  1223.     MAX_MESSAGE,                    "Invalid Return Code Value"
  1224. };
  1225.  
  1226. CPICERR_MESSAGE cpicerr_rc_classes[] = {
  1227.     BACKOUT_RECEIVED,   "BACKOUT_RECEIVED",
  1228.     CONTINUE,           "CONTINUE",
  1229.     ERROR_RECEIVED,     "ERROR_RECEIVED",
  1230.     SECURITY_NOT_VALID, "SECURITY_NOT_VALID",
  1231.     RETRY_CONV,         "RETRY_CONVERSATION",
  1232.     RETRY_CONV_BO,      "RETRY_CONVERSATION_BACKOUT",
  1233.     RETRY_VERB,         "RETRY_LAST_VERB",
  1234.     UNRECOVERABLE,      "UNRECOVERABLE",
  1235.     UNRECOVERABLE_BO,   "UNRECOVERABLE_BACKOUT",
  1236.     MAX_MESSAGE,        "Invalid Return Code Class"
  1237. };
  1238.  
  1239. CPICERR_MESSAGE cpicerr_states_conv[] = {
  1240.     CM_INITIALIZE_STATE,            "Initialize state",
  1241.     CM_SEND_STATE,                  "Send state",
  1242.     CM_RECEIVE_STATE,               "Receive state",
  1243.     CM_SEND_PENDING_STATE,          "Send pending state",
  1244.     CM_CONFIRM_STATE,               "Confirm state",
  1245.     CM_CONFIRM_SEND_STATE,          "Confirm send state",
  1246.     CM_CONFIRM_DEALLOCATE_STATE,    "Confirm deallocate state",
  1247.     CM_DEFER_RECEIVE_STATE,         "Defer receive state",
  1248.     CM_DEFER_DEALLOCATE_STATE,      "Defer deallocate state",
  1249.     CM_SYNC_POINT_STATE,            "Sync point state",
  1250.     CM_SYNC_POINT_SEND_STATE,       "Sync point send state",
  1251.     CM_SYNC_POINT_DEALLOCATE_STATE, "Sync point deallocate state",
  1252.     CMECS_NOT_SUPPORTED,            "CMECS not supported",
  1253.     MAX_MESSAGE,                    "Invalid Conversation State value"
  1254. };
  1255.  
  1256. CPICERR_MESSAGE cpicerr_sync_levels[] = {
  1257.     CM_NONE,            "None",
  1258.     CM_CONFIRM,         "Confirm",
  1259.     CM_SYNC_POINT,      "Sync Point",
  1260.     MAX_MESSAGE,        "Invalid Sync Level value"
  1261. };
  1262.  
  1263. CPICERR_MESSAGE cpicerr_conv_types[] = {
  1264.     CM_BASIC_CONVERSATION , "Basic",
  1265.     CM_MAPPED_CONVERSATION, "Mapped",
  1266.     CMECT_NOT_SUPPORTED,    "CMECT not supported",
  1267.     MAX_MESSAGE,            "Invalid conversation type value"
  1268. };
  1269.  
  1270. CPICERR_MESSAGE_LIST message_list[] = {
  1271.     CPIC_SYNC_LEVELS,   cpicerr_sync_levels,
  1272.     CPIC_CONV_TYPES,    cpicerr_conv_types,
  1273.     CPIC_STATES_CONV,   cpicerr_states_conv,
  1274.     CPIC_RC_CLASSES,    cpicerr_rc_classes,
  1275.     CPIC_RETURN_CODES,  cpicerr_return_codes,
  1276.     CPIC_VERBS_SHORT,   cpicerr_verbs_short,
  1277.     CPIC_VERBS_LONG,    cpicerr_verbs_long,
  1278.     MAX_MESSAGE,        NULL
  1279. };
  1280.  
  1281. /*****************************************************************************
  1282.  *
  1283.  *  cpicerr_get_message()
  1284.  *
  1285.  *****************************************************************************/
  1286. char *
  1287. cpicerr_get_message(CPICERR_MESSAGE_TYPE message_type, CM_INT32 index)
  1288. {
  1289.     unsigned int count;                     /* counter through the array     */
  1290.  
  1291.     CPICERR_MESSAGE * messages;
  1292.  
  1293.     for (count = 0; message_list[count].type < MAX_MESSAGE ; count++ ) {
  1294.         if (message_list[count].type == message_type) break;
  1295.     }
  1296.  
  1297.     if ( (messages = message_list[count].list) == NULL ) {
  1298.         return "Message list not found.";
  1299.     }
  1300.  
  1301.     for (count = 0; messages[count].index < MAX_MESSAGE; count++) {
  1302.        if (messages[count].index == index) break;
  1303.     }
  1304.     return messages[count].message;
  1305. }
  1306.  
  1307.  
  1308.  
  1309. /*****************************************************************************
  1310.  *
  1311.  *  cpicerr_show_product_info
  1312.  *
  1313.  *****************************************************************************/
  1314. void
  1315. cpicerr_show_product_info(CPICERR * cpicerr,
  1316.                           FILE * target_file)
  1317. {
  1318.     FILE * temp;
  1319.     temp = target_file;  /* avoids warnings */
  1320.  
  1321.     if (cpicerr->conv_rc == CM_ALLOCATE_FAILURE_NO_RETRY ||
  1322.         cpicerr->conv_rc == CM_ALLOCATE_FAILURE_RETRY ) {
  1323.         if (get_machine_mode()) {
  1324. #ifdef GET_OS2_SENSE_DATA
  1325.         cpicerr_os2_appc_allocate(cpicerr, target_file);
  1326. #endif
  1327.         }
  1328.  
  1329.     }
  1330. }
  1331.  
  1332. #ifdef GET_OS2_SENSE_DATA
  1333.  
  1334. cpicerr_os2_appc_allocate(CPICERR * cpicerr,
  1335.                           FILE * target_file)
  1336. /*
  1337.  * This procedure retries the allocate that failed in CPI-C.  We are not
  1338.  * retrying the allocate to establish the connection, but to get more
  1339.  * error information about why the first allocate failed.
  1340.  *
  1341.  * The OS/2 APPC api is used to extract the sense data, which provides
  1342.  * a more specify reason for an allocation failure.
  1343.  */
  1344. {
  1345.    TP_STARTED tp_started;                    /* Declare a verb control block */
  1346.    TP_STARTED *ptr_tp_started = (TP_STARTED *)&tp_started;
  1347.    USHORT length;                            /* length of lu_alias           */
  1348.    char   plu_alias[8+1];
  1349.    char   fqplu_name[17+1];
  1350.  
  1351.    ALLOCATE allocate;                        /* Declare a verb control block */
  1352.    ALLOCATE *ptr_allocate = (ALLOCATE *)&allocate;
  1353.  
  1354.    TP_ENDED tp_ended;                        /* Declare a verb control block */
  1355.    TP_ENDED *ptr_tp_ended = (TP_ENDED *)&tp_ended;
  1356.  
  1357.  
  1358.    CLEAR_VCB(tp_started);                    /* Zero the verb control block  */
  1359.    tp_started.opcode = AP_TP_STARTED;        /* APPC verb - TP_STARTED       */
  1360.  
  1361.    memset( tp_started.lu_alias, (int)'\0', sizeof(tp_started.lu_alias));
  1362.  
  1363.    BLANK_STRING(tp_started.tp_name);         /* Set 64-byte string to blanks */
  1364.    ascii_to_ebcdic_field(tp_started.tp_name,
  1365.                          sizeof(tp_started.tp_name));
  1366.  
  1367.    APPC ((ULONG) (TP_STARTED far *)ptr_tp_started); /* Issue the verb        */
  1368.  
  1369.    if (tp_started.primary_rc == AP_OK) {
  1370.        CLEAR_VCB(allocate);                  /* Zero the vcb                 */
  1371.        allocate.opcode = AP_B_ALLOCATE;      /* Verb - ALLOCATE              */
  1372.        allocate.opext = AP_MAPPED;           /* Basic Conversation type      */
  1373.  
  1374.                                              /* Set the TP_ID */
  1375.        memcpy (allocate.tp_id, tp_started.tp_id, sizeof(allocate.tp_id));
  1376.        allocate.sync_level = AP_CONFIRM;     /* Sync level-confirm           */
  1377.        allocate.rtn_ctl = AP_WHEN_SESSION_FREE;/* avoid deadlock             */
  1378.        allocate.security = AP_NONE;          /* Set security type            */
  1379.  
  1380.        if (!parse_destination(cpicerr->partner_LU_name,
  1381.                               plu_alias,
  1382.                               fqplu_name)) {
  1383.           if ((length = strlen(plu_alias)) != 0) {
  1384.              BLANK_STRING(allocate.plu_alias);
  1385.              memcpy ( allocate.plu_alias,
  1386.                       plu_alias,
  1387.                       min(length, sizeof(allocate.plu_alias)));
  1388.                                              /* Set PLU_ALIAS                */
  1389.           } else {
  1390.              memset (allocate.plu_alias,(int)'\0',sizeof(allocate.plu_alias));
  1391.              BLANK_STRING(allocate.fqplu_name);  /* Set FQ PLU NAME          */
  1392.              memcpy ( allocate.fqplu_name,
  1393.                       fqplu_name,
  1394.                       min(strlen(fqplu_name), sizeof(allocate.fqplu_name)));
  1395.              TOUPPER_STRING(allocate.fqplu_name, 17);
  1396.              ascii_to_ebcdic_field(allocate.fqplu_name,
  1397.                                    sizeof(allocate.fqplu_name));
  1398.           }
  1399.  
  1400.  
  1401.        } else {
  1402.           BLANK_STRING(allocate.plu_alias);
  1403.           memcpy ( allocate.plu_alias,
  1404.                    "UNKNOWN",
  1405.                    7);
  1406.        }
  1407.  
  1408.  
  1409.        BLANK_STRING(allocate.tp_name);       /* Set 64-byte string to blanks */
  1410.        ascii_to_ebcdic_field(allocate.tp_name,
  1411.                              sizeof(allocate.tp_name));
  1412.  
  1413.        BLANK_STRING(allocate.mode_name);     /* Set 8-byte string to blanks  */
  1414.           memcpy ( allocate.mode_name,
  1415.                    cpicerr->mode_name,
  1416.                    min(strlen(cpicerr->mode_name),
  1417.                        sizeof(allocate.mode_name)));
  1418.           TOUPPER_STRING(allocate.mode_name, 8);
  1419.        ascii_to_ebcdic_field(allocate.mode_name,
  1420.                              sizeof(allocate.mode_name));
  1421.  
  1422.        APPC((ULONG) (ALLOCATE far *) ptr_allocate);  /* Issue the verb       */
  1423.  
  1424.        if (allocate.primary_rc != AP_OK) {
  1425.         fprintf(target_file,
  1426.         "\t OS/2 Sense Data: %08lX\n", SWAP4(allocate.sense_data));
  1427.  
  1428.        }
  1429.  
  1430.    } else {                                  /* Save the returned tp_id      */
  1431.        return (tp_started.primary_rc);
  1432.    }
  1433.    CLEAR_VCB(tp_ended);                      /* Zero the verb control block  */
  1434.    tp_ended.opcode = AP_TP_ENDED;            /* Set the verb opcode          */
  1435.                                              /* Set the tp_id  */
  1436.    memcpy (tp_ended.tp_id, tp_started.tp_id, sizeof(tp_ended.tp_id));
  1437.    tp_ended.type = AP_SOFT;                  /* type: AP_HARD or AP_SOFT     */
  1438.  
  1439.    APPC((ULONG) (TP_ENDED far *) ptr_tp_ended); /* Issue the verb.           */
  1440. }
  1441.  
  1442.  
  1443.  
  1444. USHORT
  1445. parse_destination(char * in_string,
  1446.                   char * plu_alias,
  1447.                   char * fqplu_name)
  1448. /*
  1449.  * This procedure is used by cpicerr_os2_appc_allocate verb
  1450.  */
  1451. {
  1452.    if (strchr(in_string, '.') != NULL) {
  1453.       if (in_string[0] == '.') {
  1454.           in_string++;
  1455.       }
  1456.       strcpy(fqplu_name, in_string);
  1457.       plu_alias[0] = '\0';
  1458.    } else {
  1459.       strcpy(plu_alias, in_string);
  1460.       fqplu_name[0] = '\0';
  1461.    }
  1462.    return 0;
  1463.  
  1464. }
  1465.  
  1466. #endif
  1467.  
  1468.